#include "include/life_cycle_contract.hpp"

ACTION life_cycle_contract::method1(eosio::name user) {
    on_call(get_self(), get_self());
    eosio::print("method1 ", user);
}

ACTION life_cycle_contract::method2(eosio::name user) {
    on_call(get_self(), get_self());
    eosio::print("method2 ", user);
    eosio::check(false, "强制事务回滚");
}

ACTION life_cycle_contract::method3(eosio::name user) {
    on_call(get_self(), get_self());
    eosio::print("method3 ", user);
}

ACTION life_cycle_contract::method4(eosio::name user) {
    on_call(get_self(), get_self());
    eosio::print("method4 eosio_exit 退出 ", user);
    eosio::eosio_exit(0); // 事务正常
}

ACTION life_cycle_contract::method5(eosio::name user) {
    eosio::print("method5 ", user, "\n");
    eosio::execute_action(get_self(), get_self(), &life_cycle_contract::method1);
}

[[eosio::on_notify("eosio.token::transfer")]] void life_cycle_contract::eos_transfer() {
    on_call(get_self(), get_self());
    eosio::print("eos transfer");
}

void life_cycle_contract::on_call(eosio::name contract_name, eosio::name ram_payer) {
    info_table info_configs(contract_name, contract_name.value);
    info config = info_configs.get_or_create(ram_payer, info{
        .call_num = 0, 
        .last_call_time = eosio::current_time_point()
    });
    config.call_num++;
    config.last_call_time = eosio::current_time_point();
    info_configs.set(config, ram_payer);
}

extern "C" {
    bool pre_dispatch(eosio::name receiver, eosio::name code, eosio::name action) {
        print_f("pre_dispatch : % % %\n", receiver, code, action);
        life_cycle_contract::on_call(receiver, receiver); // 没有异常 事务会提交
        // 除了 method1 和 method2 其它的 会不执行
        if (
            action == eosio::name("method1") || 
            action == eosio::name("method2") ||
            (code == eosio::name("eosio.token") && action == eosio::name("transfer"))
        ) {
            eosio::print("pre_dispatch if \n");
            return true;
        }
        return true;
    };

    // bug Error: error: else expression without matching if
    bool post_dispatch(eosio::name receiver, eosio::name code, eosio::name action) {
        print_f("post_dispatch : % % %\n", receiver, code, action);
        return true;
    };

    // apply 所有 action 的 入口 添加 后 pre_dispatch 和
    // post_dispatch 会失效
    [[noreturn]] void apply(eosio::name receiver, eosio::name code, eosio::name action) {
        eosio::print("[apply] receiver: ", receiver, ",code:", code, ",action:", action, "\n");
        if (code == receiver) {
            switch (action.value) {
                // 合约中action的暴露
                EOSIO_DISPATCH_HELPER(life_cycle_contract, (method1)(method2)(method3)(method4)(method5))
            }
            // 使用eosiomeetone合约的transfer给hello合约转账时才会触发
        } else if (code == eosio::name("eosio.token") && action == eosio::name("transfer")) {
            eosio::datastream<const char *> ds = eosio::datastream<const char *>(nullptr, 0);
            // 执行hello合约的on_transfer方法
            eosio::execute_action(receiver, code, &life_cycle_contract::eos_transfer);
        }
        eosio::eosio_exit(0);
    }
}